﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Web;
using System.Web.Caching;
using System.Web.Hosting;
using Ue.Core;
using Ue.Core.FileSystems;

namespace Ue.Components.FileWatcher
{
    public class CacheDependencyFileMonitor : IFileMonitor
    {
        private readonly string cacheKey;
        private readonly Action<IFileMonitor> fileChangeCallback;
        private readonly IFolder folder;

        public CacheDependencyFileMonitor(string virtualPath, string filter, bool isContinued, Action<IFileMonitor> fileChangeCallback, WatcherChangeTypes changeTypes)
            : this(new Folder(new VirtualFolderRoot()), virtualPath, filter, isContinued, fileChangeCallback, changeTypes) { }

        public CacheDependencyFileMonitor(IFolder folder,string virtualPath, string filter, bool isContinued, Action<IFileMonitor> fileChangeCallback, WatcherChangeTypes changeTypes)
        {
            this.folder = folder;

            this.Filter = filter;
            this.IsContinued = IsContinued;

            this.cacheKey = this.BuildKey(virtualPath);
            this.fileChangeCallback = fileChangeCallback;

            this.AddToCache(this.BuildCacheDependency());
        }

        #region IFileMonitor 成员

        public string DirectoryPath { get; private set; }

        public string Filter { get; private set; }

        public WatcherChangeTypes ActionTypes { get; private set; }

        public bool IsContinued { get; private set; }

        public void Release()
        {
            HostingEnvironment.Cache.Remove(this.cacheKey);
        }

        #endregion

        private void AddToCache(CacheDependency cacheDependency)
        {
            HostingEnvironment.Cache.Add(
                this.cacheKey,
                string.Empty,
                cacheDependency,
                Cache.NoAbsoluteExpiration,
                Cache.NoSlidingExpiration,
                CacheItemPriority.NotRemovable,
                this.CacheCallback);
        }

        private void CacheCallback(string key, object value, CacheItemRemovedReason cacheItemRemovedReason)
        {
            if (this.fileChangeCallback != null)
            {
                this.fileChangeCallback(this);
            }

            if (this.IsContinued)
            {
                this.AddToCache(this.BuildCacheDependency());
            }
        }

        private CacheDependency BuildCacheDependency()
        {
            return HostingEnvironment.VirtualPathProvider.GetCacheDependency(
                this.DirectoryPath,
                this.folder.GetFiles(this.DirectoryPath, this.Filter),
                DateTime.UtcNow);
        }

        private string BuildKey(string virtualPath)
        {
            return Guid.NewGuid().ToString("n") + virtualPath;
        }
    }
}
